#!/usr/local/bin/python

import string, sys, pickle, cmd, imaplib, getpass, smtplib
from email.mime.text import MIMEText

# DEFINED VARIABLES
servername = 'students.iiit.ac.in'
port_imap = 143
num_of_tries = 3


#--------------------------------------------------------------------AUTHENTICATION------------------------------------------------------------
try:
	# Connect to thr server
	M = imaplib.IMAP4(servername, port_imap)
except:
	print 'Cannot connect to the server'
	sys.exit(0)

flag = 0
i = 0

while((i < num_of_tries) and flag==0):
	try:
		username = raw_input( "Username: ")
		password = getpass.getpass()
		M.login(username, password)
		flag = 1
		print "User Authenticated"
		print
	except:
		print 'Authentication Failure'
		print
		i = i+1

if i==num_of_tries :
	sys.exit(0)

S = smtplib.SMTP(servername)
#------------------------------------------------------------------------------------------------------------------------------------------------

#GLOBAL VARIABLES AND INITIALIZATION

curr_folder_name = 'INBOX'
num_curr_mail = 0
flag_list = []

fp = open('flagList','r+')
flag_list = pickle.load(fp)

#------------------------------------------------------------------------------------------------------------------------------------------------

class MailClient(cmd.Cmd):

	def __init__(self):
		cmd.Cmd.__init__(self)
		self.prompt = "WebMail Client>> "

	def help_ListSubFolders(self):
		print "Lists Subscribed Folders"
	
	def help_ListAllFolders(self):
		print "Lists All Folders"

	def help_SelectFolder(self):
		print "Select a particular folder or just enter Select to select INBOX"

	def help_CreateFolder(self):
		print "Create a new folder"

	def help_DeleteFolder(self):
		print "Delete a existing folder"

	def help_RenameFolder(self):
		print "Rename a existing folder"

	def help_SubscribeFolder(self):
		print "Subscribe a particular folder"

	def help_UnSubscribeFolder(self):
		print "Unsubscribe a particular folder"

	def help_ListMails(self):
		print "List the mails (Headers) of the selected Folder"


	def help_ViewMail(self):
		print "View the content of a mail. Syntax: ViewMail <msg_num1>,<msg_num2>.."

	def help_CopyMail(self):
		print "Copy mail from one folder to another"
	
	def help_MoveMail(self):
		print "Move mail from one folder to another"

	def help_DeleteMail(self):
		print "Moves mail to Trash"

	def help_ExpungeTrash(self):
		print "Permenantly deletes all the mails in Trash Folder"

	def help_ViewFlagList(self):
		print "View the list of all the Flags/Labels"

	def help_AddDeleteFlag(self):
		print "Add/Delete Flags from User's Flag List"

	def help_FlagMail(self):
		print "Add a particular flag to a mail"

	def help_UnFlagMail(self):
		print "Remove a particular flag from a mail"

	def help_SendMail(self):
		print "Compose and Send mail"

	def help_SearchMail(self):
		print "Search mails in your mailbox"

	def help_Exit(self):
		print "exit the module"

	def do_ListSubFolders(self, line):
		global M
		typ, lmbox = M.lsub()
		print
		for folder in lmbox:
			ptr = folder.rfind('"',0,-1)
			print folder[ptr+1 : -1]

	def do_ListAllFolders(self, line):
		global M
		typ, lmbox = M.list()
		print
		for folder in lmbox:
			ptr = folder.rfind('"', 0, -1)
			print folder[ptr+1 : -1]

	def do_SelectFolder(self, line):
		global M
		global num_curr_mail
		global curr_folder_name

		if(line==""):
			typ, mbox = M.select()
			num_curr_mail = int(mbox[0])
			print "Number of mails in the folder: " + str(num_curr_mail)
		else:
			try:
				typ, mbox = M.select(line)
				num_curr_mail = int(mbox[0])
				curr_folder_name = line
				print "Number of mails in the folder: " + str(num_curr_mail)
			except:
				print "Invalid Folder Name"

	def do_CreateFolder(self, fname):
		if fname=="":
			fname = raw_input("Enter the folder name: ")
		typ, msg = M.create(fname)
		print msg[0]

	def do_DeleteFolder(self, fname):
		if fname=="":
			fname = raw_input("Enter the folder name: ")
		typ, msg = M.delete(fname)
		print msg[0]

	def do_RenameFolder(self, old_fname):
		if old_fname=="":
			old_fname = raw_input("Enter the old folder name: ")
		new_fname = raw_input("Enter the new folder name: ")

		typ, msg = M.rename(old_fname, new_fname)
		print msg[0]

	def do_SubscribeFolder(self, fname):
		if fname=="":
			fname = raw_input("Enter the folder name: ")
		typ, msg = M.subscribe(fname)
		print msg[0]

	def do_UnSubscribeFolder(self, fname):
		if fname=="":
			fname = raw_input("Enter the folder name: ")
		typ, msg = M.unsubscribe(fname)
		print msg[0]

	def do_ListMails(self, line):
		global M
		global num_curr_mail

		print
		for i in range(num_curr_mail, 0, -1):
			print "Message Number: "  + str(i)
			typ, msg = M.fetch(str(i), '(BODY[HEADER.FIELDS (SUBJECT FROM TO)])')
			print msg[0][1][:-3]
			
			typ, msg = M.fetch(str(i),'(FLAGS INTERNALDATE)')
			ptr1 = msg[0].find('INTERNALDATE')
			print 'Date: ' + msg[0][ptr1+14 : -2]
			
			ptr1 = msg[0].find('FLAGS')
			ptr1 = ptr1+7
			ptr2 = msg[0].find(')',ptr1)
			print 'Flags: ' + msg[0][ptr1:ptr2]
			print '---------------------------------------------------------------------------------\n'

	def do_ViewMail(self, line):
		global M

		print
		if line=="":
			line = raw_input("Enter the message number: ")
		try:
			typ, msg = M.fetch(str(line), '(BODY[TEXT])')
			for i in range(0,len(msg),2):
				temp = msg[i][0].split(' ')
				print "Message Number: " + str(temp[0]) + "\n"
				print msg[i][1]
				print '---------------------------------------------------------------------------------\n'
		except:
		 	print "Invalid Message Number"

	def do_CopyMail(self, line):
		global M
		global curr_folder_name
		global num_curr_mail

		msg_no = raw_input("Enter the message numbers of the messages to be copied: ")
		fname = raw_input("Enter the folder name where the messages are to be copied: ")
		try:
			if curr_folder_name=='Trash':
				M.store(msg_no, '-FLAGS', '\\Deleted')
			M.copy(msg_no, fname)
			
			if curr_folder_name=='Trash':
				M.store(msg_no, '+FLAGS', '\\Deleted')
			print "Messages successfully copied"
		except:
			print "Invalid message set or folder name"

	def do_MoveMail(self, line):
		global M
		global curr_folder_name
		global num_curr_mail
		
		msg_no = raw_input("Enter the message numbers of the messages to be moved: ")
		fname = raw_input("Enter the folder name where the messages are to be moved: ")
		try:
			if curr_folder_name=='Trash':
				M.store(msg_no, '-FLAGS', '\\Deleted')
			M.copy(msg_no, fname)
			
			M.store(msg_no, '+FLAGS', '\\Deleted')
			if curr_folder_name != 'Trash':
				M.expunge()
				typ, mbox = M.select(curr_folder_name)
				num_curr_mail = int(mbox[0])
			print "Messages successfully moved"
		except:
			print "Invalid message set or folder name"

	def do_DeleteMail(self, msg_no):
		global M
		global curr_folder_name
		global num_curr_mail
		
		if msg_no=="":
			msg_no = raw_input("Enter the message numbers of the messages to be deleted: ")
			
		M.store(msg_no, '+FLAGS', '\\Deleted')
		M.copy(msg_no, 'Trash')
		M.expunge()
		typ, mbox = M.select(curr_folder_name)
		num_curr_mail = int(mbox[0])
		print "Messages moved to Trash"

	def do_ExpungeTrash(self, line):
		global M
		global curr_folder_name
		global num_curr_mail

		typ, mbox = M.select('Trash')
		M.store('1:' + str(mbox[0]), '+FLAGS', '\\Deleted')
		M.expunge()
		if curr_folder_name == 'Trash':
			num_curr_mail = 0

		M.select(curr_folder_name)

	def do_ViewFlagList(self, line):
		global flag_list

		for flag in flag_list:
			print flag

	def do_AddDeleteFlag(self, line):
		global flag_list

		opt = raw_input("Add/Delete: ")
		flagName = raw_input("Enter the flag name: ")

		opt = opt.lower()
		if opt=='add':
			if flagName in flag_list:
				print "Flag already exists"
			else:
				flag_list.append(flagName)
				pickle.dump(flag_list,fp)
				print "Flag successfully added"
		elif opt=='delete':
			if flagName not in flag_list:
				print "Flag does not exist"
			else:
				flag_list.remove(flagName)
				pickle.dump(flag_list,fp)
				print "Flag successfully deleted"
		else:
			print "Error in the option entered"

	def do_FlagMail(self, line):
		global M
		global flag_list

		msg_no = raw_input("Enter the message set: ")
		fname = raw_input("Enter the flag name: ")

		if fname in flag_list:
			M.store(msg_no, '+FLAGS', fname)
			print "Mails flagged successfully"
		else:
			print "Either Flag name doesn't exit or error in message set"

	def do_UnFlagMail(self, line):
		global M
		global flag_list

		msg_no = raw_input("Enter the message set: ")
		fname = raw_input("Enter the flag name: ")

		if fname in flag_list:
			M.store(msg_no, '-FLAGS', fname)
			print "Mails un-flagged successfully"
		else:
			print "Either Flag name doesn't exit or error in message set"

	def do_SendMail(self, line):
		global S
		global username
		global servername

		txt = ''
		print "Enter your message: "
		while 1:
			try:
				line = raw_input()
			except EOFError:
				break
			if not line:
				break
			txt = txt + line + '\n'
		From = username + '@' + servername
		
		To = raw_input("To: ")
		Subject = raw_input("Subject: ")

		msg = MIMEText(txt)
		msg['To'] = To
		msg['Subject'] = Subject
		msg['From'] = From
		
		S.sendmail(From, [To], msg.as_string())

	def do_Exit(self, line):
		global M
		global S
		M.logout()
		S.quit()
		sys.exit(0)

		
client = MailClient()
client.cmdloop()
